/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const SYMBOLS_SOME_VALUE_2: number = 2;
const SYMBOLS_SOME_VALUE_3: number = 3;
const SYMBOLS_SOME_VALUE_4: number = 4;
const SYMBOLS_SOME_VALUE_5: number = 5;
const SYMBOLS_SOME_VALUE_6: number = 6;
const SYMBOLS_SOME_VALUE_7: number = 7;
const SYMBOLS_SOME_VALUE_8: number = 8;
const SYMBOLS_SOME_VALUE_9: number = 9;
const SYMBOLS_SOME_VALUE_12: number = 12;
const SYMBOLS_SOME_VALUE_13: number = 13;
const SYMBOLS_SOME_VALUE_14: number = 14;
const SYMBOLS_SOME_VALUE_15: number = 15;

// B3 types
export let nVoid: string = 'Void';
export let nInt32: string = 'Int32';
export let nInt64: string = 'Int64';
export let nFloat: string = 'Float';
export let dDouble: string = 'Double';

// Arg type
export let GP: string = 'GP';
export let FP: string = 'FP';

// Stack slot kind
export let locked: string = 'Locked';
export let spill: string = 'Spill';

// Frequency class
export let normal: string = 'Normal';
export let rare: string = 'Rare';

// Relational conditions
export let equal: string = 'Equal';
export let notEqual: string = 'NotEqual';
export let above: string = 'Above';
export let aboveOrEqual: string = 'AboveOrEqual';
export let below: string = 'Below';
export let belowOrEqual: string = 'BelowOrEqual';
export let greaterThan: string = 'GreaterThan';
export let greaterThanOrEqual: string = 'GreaterThanOrEqual';
export let lessThan: string = 'LessThan';
export let lessThanOrEqual: string = 'LessThanOrEqual';

export function relCondCode(cond: string): number {
  switch (cond) {
    case equal:
      return SYMBOLS_SOME_VALUE_4;
    case notEqual:
      return SYMBOLS_SOME_VALUE_5;
    case above:
      return SYMBOLS_SOME_VALUE_7;
    case aboveOrEqual:
      return SYMBOLS_SOME_VALUE_3;
    case below:
      return SYMBOLS_SOME_VALUE_2;
    case belowOrEqual:
      return SYMBOLS_SOME_VALUE_6;
    case greaterThan:
      return SYMBOLS_SOME_VALUE_15;
    case greaterThanOrEqual:
      return SYMBOLS_SOME_VALUE_13;
    case lessThan:
      return SYMBOLS_SOME_VALUE_12;
    case lessThanOrEqual:
      return SYMBOLS_SOME_VALUE_14;
    default:
      throw new Error('Bad rel cond');
  }
}

// Result conditions
export let overflow: string = 'Overflow';
export let signed: string = 'Signed';
export let positiveOrZero: string = 'PositiveOrZero';
export let zero: string = 'Zero';
export let nonZero: string = 'NonZero';

export function resCondCode(cond: string): number {
  switch (cond) {
    case overflow:
      return 0;
    case signed:
      return SYMBOLS_SOME_VALUE_8;
    case positiveOrZero:
      return SYMBOLS_SOME_VALUE_9;
    case zero:
      return SYMBOLS_SOME_VALUE_4;
    case nonZero:
      return SYMBOLS_SOME_VALUE_5;
    default:
      throw new Error('Bad res cond: (cond)');
  }
}

// Double conditions
export let doubleEqual: string = 'DoubleEqual';
export let doubleNotEqual: string = 'DoubleNotEqual';
export let doubleGreaterThan: string = 'DoubleGreaterThan';
export let doubleGreaterThanOrEqual: string = 'DoubleGreaterThanOrEqual';
export let doubleLessThan: string = 'DoubleLessThan';
export let doubleLessThanOrEqual: string = 'DoubleLessThanOrEqual';
export let doubleEqualOrUnordered: string = 'DoubleEqualOrUnordered';
export let doubleNotEqualOrUnordered: string = 'DoubleNotEqualOrUnordered';
export let doubleGreaterThanOrUnordered: string = 'DoubleGreaterThanOrUnordered';
export let doubleGreaterThanOrEqualOrUnordered: string = 'DoubleGreaterThanOrEqualOrUnordered';
export let doubleLessThanOrUnordered: string = 'DoubleLessThanOrUnordered';
export let doubleLessThanOrEqualOrUnordered: string = 'DoubleLessThanOrEqualOrUnordered';

export function doubleCondCode(cond: string): number {
  let bitInvert = 0x10;
  let bitSpecial = 0x20;
  switch (cond) {
    case doubleEqual:
      return SYMBOLS_SOME_VALUE_4 | bitSpecial;
    case doubleNotEqual:
      return SYMBOLS_SOME_VALUE_5;
    case doubleGreaterThan:
      return SYMBOLS_SOME_VALUE_7;
    case doubleGreaterThanOrEqual:
      return SYMBOLS_SOME_VALUE_3;
    case doubleLessThan:
      return SYMBOLS_SOME_VALUE_7 | bitInvert;
    case doubleLessThanOrEqual:
      return SYMBOLS_SOME_VALUE_3 | bitInvert;
    case doubleEqualOrUnordered:
      return SYMBOLS_SOME_VALUE_4;
    case doubleNotEqualOrUnordered:
      return SYMBOLS_SOME_VALUE_5 | bitSpecial;
    case doubleGreaterThanOrUnordered:
      return SYMBOLS_SOME_VALUE_2 | bitInvert;
    case doubleGreaterThanOrEqualOrUnordered:
      return SYMBOLS_SOME_VALUE_6 | bitInvert;
    case doubleLessThanOrUnordered:
      return SYMBOLS_SOME_VALUE_2;
    case doubleLessThanOrEqualOrUnordered:
      return SYMBOLS_SOME_VALUE_6;
    default:
      throw new Error('Bad cond');
  }
}

// Define pointerType()
export let PTR = 64;
